/**
 * Trabalho PI - Filtros Espaciais
 *
 *  Thales Luis Rodrigues Sabino de Alcantara Bourbon Guacamole em Pedra Dura Tanto Bate Até Kifura
 *  Eder Knop de Castro Alves Moacir Junior Haduken Tek Tek Turugen
 *  Tássio de Almeida Perez Tiger Mocotó
 *
 */
#include "pixelMap.h"
#include "math.h"

#include <GL/gl.h>
#include <GL/glut.h>

#ifdef WIN32
    #include <windows.h>
    #include <GL/glui.h>
#else
    #include <glui.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <math.h>

/**
 * Variáveis do GLUI
 */
#define GLUI_BUTTON_LOAD_IMAGE     0xf0
#define GLUI_BUTTON_APPLY          0xf1

#define GLUI_RADIO_OP              0xf2
#define GLUI_RADIO_PASSA_ALTA      0
#define GLUI_CHECK_PASSA_ALTA_H    0xf3
#define GLUI_CHECK_PASSA_ALTA_V    0xf4

#define GLUI_RADIO_PASSA_BAIXA     1
#define GLUI_RADIO_PASSA_BAIXA_TAM 0xf5

#define FALSE 0
#define TRUE 1

GLUI *glui;

char panel_edit_image[sizeof(GLUI_String)];

GLUI_Panel      *panel_operation;
GLUI_RadioGroup *panel_operation_radiogroup;
int op;

GLUI_Panel      *panel_passa_alta;
GLUI_RadioGroup *panel_passa_alta_radiogroup;
int filtro_passa_alta;
int passa_alta_horizontal = TRUE;
int passa_alta_vertical   = FALSE;

GLUI_Panel      *panel_passa_baixa;
GLUI_RadioGroup *panel_passa_baixa_radiogroup;
GLUI_RadioGroup *panel_passa_baixa_radiogroup_tamanho;
int filtro_passa_baixa;
int filtro_passa_baixa_tamanho;

PixelMap *img_orig = NULL;
PixelMap *img_dest  = NULL;

PixelMap *img_show = NULL;

uByte *data;

int main_window;
int viewer; //id da janela de visualização

float filtro_media_3x3[9] = {
    1/9, 1/9, 1/9,
    1/9, 1/9, 1/9,
    1/9, 1/9, 1/9
};


float filtro_media_5x5[25] = {
    1/25, 1/25, 1/25, 1/25, 1/25,
    1/25, 1/25, 1/25, 1/25, 1/25,
    1/25, 1/25, 1/25, 1/25, 1/25,
    1/25, 1/25, 1/25, 1/25, 1/25,
    1/25, 1/25, 1/25, 1/25, 1/25,
};


float filtro_media_7x7[49] = {
    1/49, 1/49, 1/49, 1/49, 1/49,
    1/49, 1/49, 1/49, 1/49, 1/49,
    1/49, 1/49, 1/49, 1/49, 1/49,
    1/49, 1/49, 1/49, 1/49, 1/49,
    1/49, 1/49, 1/49, 1/49, 1/49,
};

float filtro_media_3x3[9] = {
    1/9, 1/9, 1/9,
    1/9, 1/9, 1/9,
    1/9, 1/9, 1/9
};


using namespace std;

void display() {
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   if( img_show ) img_show->ViewImage();
   //if( img_orig ) img_orig->ViewImage();
   glutSwapBuffers();
}

void key(unsigned char key, int x, int y) {
    switch (key) {
        case 27 :
        case 'q':
            exit(0);
        break;
    }

    glutPostRedisplay();
}


enum filtro_media_tam_enum{ FILTRO_TAM_3X3, FILTRO_TAM_5X5, FILTRO_TAM_7X7 };

void filtro_media( filtro_media_tam_enum tamanho ) {
//    if( tamanho == FILTRO_TAM_3X3 ) {
//
//    }
}

void filtro_gaussiano( filtro_gauss_tam_enum tamanho ) {
    if( img_dest ) delete img_dest;

    img_dest = new PixelMap();
    data = new uByte[ img_orig->width * img_orig->height * 3 ];
    img_dest->CreateImage( img_orig->width, img_orig->height, data );

    for( int y = 0; y < img_dest->GetHeight(); y++ ) {
        for( int x = 0; x < img_dest->GetWidth(); x++ ) {


            int index   = ( y * width + x ) * 3;
            int index2  = ( y * less_img->GetWidth() + x ) * 3;

            int r = 0;
            int g = 0;
            int b = 0;

            if( (y > less_img->GetHeight()) || (x > less_img->GetWidth()) ) {
              img_dest->data[index]   = bigger_img->data[index];
              img_dest->data[index+1] = bigger_img->data[index+1];
              img_dest->data[index+2] = bigger_img->data[index+2];
            }
            else {
              switch( which_op ) {
                  case ARITHMETIC_OP_SUM:
                      r = bigger_img->data[index]   + less_img->data[index2];
                      g = bigger_img->data[index+1] + less_img->data[index2+1];
                      b = bigger_img->data[index+2] + less_img->data[index2+2];

                      img_dest->data[index]   = ( r >= 255 ) ? 255 : r;
                      img_dest->data[index+1] = ( g >= 255 ) ? 255 : g;
                      img_dest->data[index+2] = ( b >= 255 ) ? 255 : b;
                      break;

                  case ARITHMETIC_OP_SUB:
                      r = bigger_img->data[index]   - less_img->data[index2];
                      g = bigger_img->data[index+1] - less_img->data[index2+1];
                      b = bigger_img->data[index+2] - less_img->data[index2+2];

                      img_dest->data[index]   = ( r <= 0 ) ? 0 : r;
                      img_dest->data[index+1] = ( g <= 0 ) ? 0 : g;
                      img_dest->data[index+2] = ( b <= 0 ) ? 0 : b;
                      break;

                  case ARITHMETIC_OP_MID:
                      r = ( bigger_img->data[index]   + less_img->data[index2]   ) * 0.5f;
                      g = ( bigger_img->data[index+1] + less_img->data[index2+1] ) * 0.5f;
                      b = ( bigger_img->data[index+2] + less_img->data[index2+2] ) * 0.5f;

                      img_dest->data[index]   = ( r >= 255 ) ? 255 : r;
                      img_dest->data[index+1] = ( g >= 255 ) ? 255 : g;
                      img_dest->data[index+2] = ( b >= 255 ) ? 255 : b;
                      break;

                  default:
                      break;
              }
            }
        }
    }

    glutSetWindow( main_window );
    glutReshapeWindow( img_dest->GetWidth(), img_dest->GetHeight() );
    glutPostRedisplay();
}


void glui_callback( int id ) {

    switch( id ) {
        case GLUI_BUTTON_LOAD_IMAGE:
            cout << "Botao Carregar Imagem: " << panel_edit_image << endl;
            img_orig = new PixelMap( panel_edit_image );
            img_show = img_orig;
            break;

        case GLUI_BUTTON_APPLY:
            cout << "Botao Aplicar Filtro: ";
            if( panel_passa_baixa->enabled )
            switch( filtro_passa_baixa ) {

                /// Filtro da média
                case 0:

                    switch( filtro_passa_baixa_tamanho ) {

                        /// Filtro da média 3x3
                        case 0:
                            cout << "Filtro da média tamanho 3x3" << endl;
                            filtro_media( FILTRO_TAM_3X3 );
                            img_show = img_dest;
                            break;

                        /// Filtro da média 5x5
                        case 1:
                            cout << "Filtro da média tamanho 5x5" << endl;
                            filtro_media( FILTRO_TAM_5X5 );
                            img_show = img_dest;
                            break;

                        /// Filtro da média 7x7
                        case 2:
                            cout << "Filtro da média tamanho 7x7" << endl;
                            filtro_media( FILTRO_TAM_7X7 );
                            img_show = img_dest;
                            break;


                        default:
                            break;
                    }
                    break;

                /// Filtro Gaussiano
                case 1:

                    switch( filtro_passa_baixa_tamanho ) {

                        /// Filtro da média 3x3
                        case 0:
                            cout << "Filtro Gaussiano tamanho 3x3" << endl;
                            break;

                        /// Filtro da média 5x5
                        case 1:
                            cout << "Filtro Gaussiano tamanho 5x5" << endl;
                            break;

                        /// Filtro da média 7x7
                        case 2:
                            cout << "Filtro Gaussiano tamanho 5x5" << endl;
                            break;


                        default:
                            break;
                    }
            }

            if( panel_passa_alta->enabled )
            switch( filtro_passa_alta ) {
                /// Filtro de Sobel
                case 0:
                    cout << "Filtro de Sobel" << endl;
                    break;

                /// Filtro de Prewitt
                case 1:
                    cout << "Filtro de Prewitt" << endl;
                    break;

                default:
                    break;
            }

            img_show = img_dest;
            break;

        case GLUI_RADIO_OP:
            switch( op ) {
                case GLUI_RADIO_PASSA_ALTA:
                    cout << "Selecionado filtro passa alta." << endl;
                    panel_passa_alta->enable();
                    panel_passa_baixa->disable();
                    break;

                case GLUI_RADIO_PASSA_BAIXA:
                    cout << "Selecionado filtro passa baixa." << endl;
                    panel_passa_alta->disable();
                    panel_passa_baixa->enable();
                    break;

                default:
                    break;

            }
            break;

            default:
                break;

    }



    fflush( stdout );

    if(img_show) {
        glutSetWindow( main_window );
        glutReshapeWindow( img_show->GetWidth(), img_show->GetHeight() );
        glutPostRedisplay();
    }
}



void system_exit() {
    if( img_orig ) delete img_orig;
    if( img_dest ) delete img_dest;
}

int main(int argc, char *argv[]) {
    atexit( system_exit );

    glutInit( &argc, argv );

    glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
    glutInitWindowPosition( 0,0 );
    main_window = glutCreateWindow( "PixelMap Image Viewer" );
    glutDisplayFunc( display );
    glutKeyboardFunc( key );
    GLUI_Master.set_glutIdleFunc(NULL);

    /**
     * Implementação da interface com GLUI
     */
    glui = GLUI_Master.create_glui( "Control window - Filtros Espaciais", 0, 700, 50 );
    GLUI_Panel *panel_main = glui->add_panel("", GLUI_PANEL_NONE ); /// Add invisible panel to hold rest of controls

    /**
     * Configura painel principal
     */
    glui->add_edittext_to_panel( panel_main, "Imagem: ", GLUI_EDITTEXT_TEXT, panel_edit_image, -1, glui_callback );
    glui->add_button_to_panel( panel_main, "Carregar", GLUI_BUTTON_LOAD_IMAGE, glui_callback );

    panel_operation            = glui->add_panel_to_panel( panel_main, "Operacao" );
    panel_operation_radiogroup = glui->add_radiogroup_to_panel( panel_operation, &op, GLUI_RADIO_OP, glui_callback );

    glui->add_radiobutton_to_group( panel_operation_radiogroup, "Passa baixa" );
    glui->add_radiobutton_to_group( panel_operation_radiogroup, "Passa alta" );

    /**
     * Configura painel de filtros passa baixa
     */

    panel_passa_baixa = glui->add_panel_to_panel( panel_main, "Filtros passa baixa" );

    GLUI_Panel *panel_passa_baixa_filtro = glui->add_panel_to_panel( panel_passa_baixa, "Filtro" );

    panel_passa_baixa_radiogroup = glui->add_radiogroup_to_panel( panel_passa_baixa_filtro, &filtro_passa_baixa, GLUI_RADIO_PASSA_BAIXA, glui_callback );

    glui->add_radiobutton_to_group( panel_passa_baixa_radiogroup, "Media" );
    glui->add_radiobutton_to_group( panel_passa_baixa_radiogroup, "Gaussino" );

    GLUI_Panel *panel_passa_baixa_tamanho = glui->add_panel_to_panel( panel_passa_baixa, "Tamanho" );

    panel_passa_baixa_radiogroup_tamanho = glui->add_radiogroup_to_panel( panel_passa_baixa_tamanho, &filtro_passa_baixa_tamanho, GLUI_RADIO_PASSA_BAIXA_TAM, glui_callback );

    glui->add_radiobutton_to_group( panel_passa_baixa_radiogroup_tamanho, "3x3" );
    glui->add_radiobutton_to_group( panel_passa_baixa_radiogroup_tamanho, "5x5" );
    glui->add_radiobutton_to_group( panel_passa_baixa_radiogroup_tamanho, "7x7" );


    /**
     * Configura painel de filtros passa alta
     */
    panel_passa_alta = glui->add_panel_to_panel( panel_main, "Passa alta" );

    GLUI_Panel *panel_passa_alta_filtro = glui->add_panel_to_panel( panel_passa_alta, "Filtro" );

    panel_passa_alta_radiogroup = glui->add_radiogroup_to_panel( panel_passa_alta_filtro, &filtro_passa_alta, GLUI_RADIO_PASSA_ALTA, glui_callback );

    glui->add_radiobutton_to_group( panel_passa_alta_radiogroup, "Sobel" );
    glui->add_radiobutton_to_group( panel_passa_alta_radiogroup, "Prewitt" );

    GLUI_Panel *panel_passa_alta_dir = glui->add_panel_to_panel( panel_passa_alta, "Direcoes" );

    glui->add_checkbox_to_panel( panel_passa_alta_dir, "Horizontal", &passa_alta_horizontal, GLUI_CHECK_PASSA_ALTA_H, glui_callback );
    glui->add_checkbox_to_panel( panel_passa_alta_dir, "Vertical",   &passa_alta_vertical,   GLUI_CHECK_PASSA_ALTA_V, glui_callback );

    glui->add_button_to_panel( panel_main, "Aplicar", GLUI_BUTTON_APPLY, glui_callback );

    panel_passa_baixa->disable();

    glutMainLoop();

    return 0;
}
